/**
 * 众赢投顾 指标计算工具集
 */
const ZHANG_TING_INDEX = 1.1      //强势调整的安全均线周期
const DEBUG_FLAG = false

export const MMD_GET_MIN = 1
export const MMD_GET_MAX = 2
export const MMD_GET_ALL = 3

//根据传入数据返回指定周期的最大值和最小值数组
//calculator: 回调函数，如果传入则去掉field，对当日股价做回调运算
//minOrMax: 1-只获取最小值，2-只获取最大值，其他全部获取，
export function calcMaxMinOfDays(rawData, field, period, minOrMax, calculator) {
    let bestValues = []
    let worseValues = []
    let needBest = (!minOrMax || minOrMax == 2 || minOrMax == 3)
    let needWorse = (!minOrMax || minOrMax == 1 || minOrMax == 3)

    for (let i = 0; i < rawData.length; i++) {
        let current = getValue(i)

        let periodStart = i - period + 1
        if (periodStart < 0) periodStart = 0

        let best = current
        let worse = current
        for (let j = periodStart; j < i; j++) {
            let currentJ = getValue(j)
            if (currentJ > best) {
                best = currentJ
            }
            if (currentJ < worse) {
                worse = currentJ
            }
        }
        if (needBest) bestValues.push(best)
        if (needWorse) worseValues.push(worse)
    }
    
    if (needBest && needWorse) {
        return {
            best: bestValues,
            worse: worseValues
        }
    } else {
        if (needBest) return bestValues
        if (needWorse) return worseValues
    }


    function getValue(index) {
        if (calculator) {
            return calculator(rawData[index]);
        } else {
            return rawData[index][field];
        }
    }
}

//根据传入数据返回最近n的指定字段的最大值/最小值
//calculator: 回调函数，如果传入则去掉field，对当日股价做回调运算
//minOrMax: 1-只获取最小值，2-只获取最大值，其他全部获取，
export function findMaxMinOfDays(rawData, currentIndex, period, minOrMax, field, calculator) {
    let bestValue = getValue(currentIndex)
    let worseValue = bestValue
    let bestIndex = currentIndex
    let worseIndex = currentIndex
    let needBest = (!minOrMax || minOrMax == 2 || minOrMax == 3)
    let needWorse = (!minOrMax || minOrMax == 1 || minOrMax == 3)
    let result = 0
    for (let i = currentIndex; i > currentIndex - period; i--) {
        let current = getValue(i)
        if (current > bestValue) {
            bestValue = current
            bestIndex = i
        }
        if (current < worseValue) {
            worseValue = current
            worseIndex = i
        }
    }
    
    if (needBest && needWorse) {
        return {
            best: bestValue,
            bestIndex: bestIndex,
            worse: worseValue,
            worseIndex: worseIndex
        }
    } else {
        if (needBest) return bestValue
        if (needWorse) return worseValue
    }


    function getValue(index) {
        if (index < 0) return 0
        if (calculator) {
            return calculator(rawData[index])
        } else {
            return rawData[index] ? rawData[index][field] : 0
        }
    }
}

/**根据传入的计算函数，计算所有数组元素点对应的值
    rawData: 原始数据
    calculators: 自定义计算规则数据
        calculator(todayRawData, extraData){}
    extraData：辅助计算的额外数据，会传入calculator
    return: 如果只有一个数组则直接返回
*/
export function calcDays(rawData, calculators, extraData) {
    let result = []
    for (let j = 0; j < calculators.length; j++) {
        result.push([])
    }
    for (let i = 0; i < rawData.length; i++) {
        for (let j = 0; j < calculators.length; j++) {
            let calc = calculators[j]
            result[j].push(calc(rawData, i, extraData))
        }
    }
    if (result.length > 1) {
        return result
    } else {
        return result[0]
    }
}

/**根据传入的计算函数和最近天数，计算符合条件的天数
    rawData: 原始数据
    currentIndex: 当天index
    days: 用于计算的最近天数（如果传入0则计算全部范围)
    calculators: 自定义计算规则数据
        calculator(todayRawData, extraData){}
    extraData：辅助计算的额外数据，会传入calculator
    return: 如果只有一个数组则直接返回
*/
export function countDays(rawData, currentIndex, days, calculators, extraData) {
    let result = []
    for (let j = 0; j < calculators.length; j++) {
        result.push(0)
    }
    for (let i = currentIndex; i > currentIndex - days; i--) {
        for (let j = 0; j < calculators.length; j++) {
            let calc = calculators[j]
            if (calc(rawData, i, extraData)) {
                result[j] += 1
            }
        }
    }
    if (result.length > 1) {
        return result
    } else {
        return result[0]
    }
}


/**根据传入的计算函数(为空则直接判断数组元素为true)，从指定index开始往前/往后找到符合条件的第一个数组元素index
    rawData: 原始数据
    currentIndex: 当前坐标
    isBackward: 查找方向，true表示向历史方向
    calculators: 自定义计算规则数据
        calculator(todayRawData, extraData){}
    extraData：辅助计算的额外数据，会传入calculator
    return: 如果只有一个数组则直接返回
*/
export function findDays(rawData, currentIndex, isBackward, calculators, extraData) {
    let result = []
    let resolved = 0
    calculators = calculators ? calculators : []
    for (let j = 0; j < calculators.length; j++) {
        result.push(-1)
    }
    let index = currentIndex
    while ((index >= 0) && (index < rawData.length)) {
        if (calculators.length == 0) {
            if (rawData[index]) {
                result[0] = index
                break
            }
        } else {
            for (let j = 0; j < calculators.length; j++) {
                if (result[j] < 0) {
                    let calc = calculators[j]
                    if (calc(rawData, index, extraData)) {
                        result[j] = index
                        resolved ++
                    }
                }
            }
        }
        if (resolved == calculators.length) 
            break
        index = index + (isBackward ? -1 : 1)
    }
    if (result.length > 1) {
        return result
    } else {
        return result[0]
    }
}

//根据传入的计算函数，匹配计算两个数组，并把计算值数组返回
export function calcArrays(array1, array2, calculator) {
    let maxLen = Math.max(array1.length, array2.length)
    let result = []

    for (let i = 0; i < maxLen; i++) {
        result.push(calculator(array1[i]?array1[i]:0, array2[i]?array2[i]:0))
    }
    return result
}

//计算两个字符型日期的相差天数
export function calcPastDays(start, current) {
    let arr1 = current.split("-")
    let arr2 = start.split("-")
    return ((new Date(arr1[0], parseInt(arr1[1])-1, arr1[2])) - (new Date(arr2[0], parseInt(arr2[1])-1, arr2[2])))/(3600*24*1000)
}

//支持同时传入多套字段和周期，一次循环生产多个移动平均数组键值对，key=<field><period>
//fields = [{field: 'open', period: 60}]
//return {open60: [], close20: []}
export function calcMAByFields(rawData, fields) {
    let averages = {}
    let sum = {}
    for (let j = 0; j < fields.length; j++) {
        averages[fields[j].field + fields[j].period] = []
        sum[fields[j].field + fields[j].period] = 0
    }
    for (let i = 0; i < rawData.length; i++) {
        for (let j = 0; j < fields.length; j++) {
            let key = fields[j].field + fields[j].period
            let start = i - fields[j].period + 1
            if (start < 0) {
                start = 0
            }
            let currentValue = rawData[i][fields[j].field]
            sum[key] += start > 0 ? currentValue - rawData[start - 1][fields[j].field] : currentValue
            let avg = sum[key] / (i - start + 1)
            avg = Math.round(avg * 10000) / 10000
            averages[key].push(avg)
        }
    }
    return averages
}

//计算数组移动累计值
export function movingSum(values, period) {
  let sums = []
  let sum = 0
  for (let i = 0; i < values.length; i++) {
    let start = i - period + 1
    if (start < 0) {
      start = 0
    }
    sum += start > 0 ? values[i] - values[start - 1] : values[i]
    sums.push(sum)
  }
  return sums
}

//判断某日是否涨停板
export function ifZhangTing(rawData, i) {
    if (!rawData[i] || !rawData[i - 1])
        return false
    let today = rawData[i] 
    let yesterday = rawData[i - 1]
    return (today.close >= (yesterday.close * ZHANG_TING_INDEX).toFixed(2))
}

export function debug(){
    if (DEBUG_FLAG == true) {
        console.log([...arguments])
    }
}

